package com.ruoyi.business.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.ruoyi.business.constant.IBusinessConstant;
import com.ruoyi.business.domain.*;
import com.ruoyi.business.entity.*;
import com.ruoyi.business.mapper.*;
import com.ruoyi.business.service.*;
import com.ruoyi.common.core.context.SecurityContextHolder;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.web.page.PageDomain;
import com.ruoyi.common.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 模型定义Service业务层处理
 *
 * @author ruoyi
 * @date 2024-01-08
 */
@Service
@Slf4j
public class ExtModelDefServiceImpl implements IExtModelDefService
{
    @Autowired
    private ExtModelDefMapper extModelDefMapper;
    @Autowired
    private IExtModelDatasourceService extModelDatasourceService;
    @Autowired
    private IExtBusinessFunctionService extBusinessFunctionService;
    @Lazy
    @Autowired
    private IExtModelFieldService extModelFieldService;
    private ExtModelDefInstanceMapper extModelDefInstanceMapper;
    @Autowired
    private IExtModelBusinessFunctionRelaService extModelBusinessFunctionRelaService;
    @Autowired
    private  IDataSourceService dataSourceService;
    @Autowired
    private ExtModelFieldRefMapper extModelFieldRefMapper;
    @Autowired
    private ExtInterfaceMapper extInterfaceMapper;
    @Autowired
    private ExtModelFieldMapper extModelFieldMapper;
    @Autowired
    private ISqlService sqlService;
    /**
     * 查询模型定义
     *
     * @param id 模型定义主键
     * @return 模型定义
     */
    @Override
    public ExtModelDef selectExtModelDefById(Long id)
    {
        return extModelDefMapper.selectExtModelDefById(id);
    }

    /**
     * 查询模型定义列表
     *
     * @param extModelDef 模型定义
     * @return 模型定义
     */
    @Override
    public List<ExtModelDef> selectExtModelDefList(ExtModelDef extModelDef)
    {
        return extModelDefMapper.selectExtModelDefList(extModelDef);
    }

    /**
     * 新增模型定义
     *
     * @param extModelDef 模型定义
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertExtModelDef(ExtModelDef extModelDef)
    {
        verifyData(extModelDef);
        extModelDef.setCreateTime(DateUtils.getNowDate());
        extModelDef.setCreateBy(SecurityUtils.getUsername());
        extModelDef.setStatus(IBusinessConstant.ACTIVE_STATE_01);
        int i=  extModelDefMapper.insertExtModelDef(extModelDef);
        bindBusinessFunction(extModelDef);
        //插入缺省字段
        insertDefaultFields(extModelDef);
        Table t = buildTable(extModelDef.getEnName(),extModelDef.getCnName());
        List<TableField> tableFields = makeTableFields(extModelDef);
        //切换数据源
        SqlSession sqlSession = null;
        String key;
        try {
            key = dataSourceService.getKey(extModelDef.getEnterpriseCode(),extModelDef.getApplicationCode(),extModelDef.getDatasourceName());
            sqlSession = dataSourceService.switchDataSource(key);
            extModelDefInstanceMapper = sqlSession.getMapper(ExtModelDefInstanceMapper.class);
            //创建表
            extModelDefInstanceMapper.createTable(t, tableFields);
        }finally {
            if(sqlSession!=null){
                sqlSession.close();
            }
        }
        return i;
    }

    /**
     * 插入缺省字段
     * @param extModelDef
     */
    private void insertDefaultFields(ExtModelDef extModelDef) {
        //根据表类型查询缺省字段
        ExtModelField extModelField = new ExtModelField();
        if(IBusinessConstant.TABLE_TYPE_01.equals(extModelDef.getTableType())){
            extModelField.setScope(IBusinessConstant.SCOPE_ENTITY_DEFAULT);
        }else{
            extModelField.setScope(IBusinessConstant.SCOPE_WORKFLOW_DEFAULT);
        }
        List<ExtModelField> defaultFields = extModelFieldService.selectExtModelFieldList(extModelField);
        for(ExtModelField defaultField:defaultFields){
            ExtModelFieldRef extModelFieldRef = new ExtModelFieldRef();
            extModelFieldRef.setExtModelFieldId(defaultField.getId());
            extModelFieldRef.setCreateBy(SecurityUtils.getUsername());
            extModelFieldRef.setCreateTime(DateUtils.getNowDate());
            extModelFieldRef.setEnName(extModelDef.getEnName());
            extModelFieldRef.setDatasourceName(extModelDef.getDatasourceName());
            extModelFieldRef.setScope(extModelField.getScope());
            extModelFieldRef.setEnterpriseCode(extModelDef.getEnterpriseCode());
            extModelFieldRef.setApplicationCode(extModelDef.getApplicationCode());
            extModelFieldRefMapper.insertExtModelFieldRef(extModelFieldRef);
        }
    }

    /**
     * 绑定业务功能
     * @param extModelDef
     */
    private void bindBusinessFunction(ExtModelDef extModelDef) {
        //绑定业务功能，插入业务功能关系表
        ExtModelBusinessFunctionRela rela = new ExtModelBusinessFunctionRela();
        rela.setDatasourceName(extModelDef.getDatasourceName());
        rela.setEnName(extModelDef.getEnName());
        rela.setBusinessCode(extModelDef.getBusinessCode());
        rela.setCreateBy(SecurityUtils.getUsername());
        rela.setCreateTime(DateUtils.getNowDate());
        rela.setEnterpriseCode(extModelDef.getEnterpriseCode());
        rela.setApplicationCode(extModelDef.getApplicationCode());
        extModelBusinessFunctionRelaService.insertExtModelBusinessFunctionRela(rela);
    }

    /**
     * 构造建表字段
     * @param extModelDef
     * @return
     */
    private List<TableField> makeTableFields(ExtModelDef extModelDef) {
        //根据表类型查询缺省字段
        ExtModelField extModelField = new ExtModelField();
        if(IBusinessConstant.TABLE_TYPE_01.equals(extModelDef.getTableType())){
            extModelField.setScope(IBusinessConstant.SCOPE_ENTITY_DEFAULT);
        }else{
            extModelField.setScope(IBusinessConstant.SCOPE_WORKFLOW_DEFAULT);
        }
        List<ExtModelField> defaultFields = extModelFieldService.selectExtModelFieldList(extModelField);
        boolean isExistId = false;
        List<TableField> tableFields = new ArrayList<>();
        Set<String> notNullFields = new HashSet<>(Arrays.asList("id", "create_by", "create_time"));
        TableField tableField;
        for(ExtModelField field:defaultFields){
            tableField = new TableField();
            tableField.setFieldName(field.getFieldEnName().toLowerCase());
            tableField.setFieldType(extModelFieldService.getDbType(field.getFieldWidth(),field.getScheme()));
            tableField.setComment(field.getFieldCnName());
            tableField.setPrimaryKey("");
            tableField.setNullLabel("");
            if(field.getFieldEnName().toLowerCase().equals("id")){
                isExistId = true;
                tableField.setAutoIncrement("AUTO_INCREMENT");
                tableField.setPrimaryKey("PRIMARY KEY");
            }
            if(notNullFields.contains(tableField.getFieldName())){
                tableField.setNullLabel("NOT NULL");
            }
            tableFields.add(tableField);
        }
        if(!isExistId)
            throw new ServiceException("缺少id字段!");
        return tableFields;
    }

    /**
     * 构造表实体
     * @param enName
     * @param cnName
     * @return
     */
    private Table buildTable(String enName, String cnName) {
        Table t = new Table();
        t.setTableName(enName);
        t.setComment(cnName);
        return  t;
    }

    /**
     * 校验数据
     * @param extModelDef
     */
    private void verifyData(ExtModelDef extModelDef) {
        //插入前校验
        if(extModelDef ==null)
            throw new ServiceException("模型对象为空！");
        //数据源名称是否存在
        Map<String,Object> searchMap = new HashMap<>();
        searchMap.put("dataSourceName", extModelDef.getDatasourceName());
        if(extModelDatasourceService.selectCount(searchMap)==0)
            throw new ServiceException("无效的数据源名称:"+ extModelDef.getDatasourceName());
        //业务编码必须存在
        searchMap.clear();
        searchMap.put("businessCode", extModelDef.getBusinessCode());
        if(extBusinessFunctionService.searchCount(searchMap)==0)
            throw new ServiceException("无效的业务编码:"+ extModelDef.getBusinessCode());
        //模型中文名+数据源名称不能重复
        searchMap.clear();
        searchMap.put("cnName",extModelDef.getCnName());
        searchMap.put("datasourceName",extModelDef.getDatasourceName());
        if(extModelDef.getId()!=null && extModelDef.getId()!=0L) {
            searchMap.put("notId", extModelDef.getId());
        }
        if(extModelDefMapper.selectCount(searchMap)>0)
            throw new ServiceException("模型中文名:"+extModelDef.getCnName()+",在数据源："+extModelDef.getDatasourceName()+"下已经存在!");
        //模型英文名+数据源名称不能重复
        searchMap.clear();
        searchMap.put("enName",extModelDef.getCnName());
        searchMap.put("datasourceName",extModelDef.getDatasourceName());
        if(extModelDef.getId()!=null && extModelDef.getId()!=0L) {
            searchMap.put("notId", extModelDef.getId());
        }
        if(extModelDefMapper.selectCount(searchMap)>0)
            throw new ServiceException("模型中文名:"+extModelDef.getCnName()+",在数据源："+extModelDef.getDatasourceName()+"下已经存在!");
    }

    /**
     * 修改模型定义
     *
     * @param extModelDef 模型定义
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateExtModelDef(ExtModelDef extModelDef)
    {
        //更新前检查
        verifyData(extModelDef);
        //更新id不能为空
        if(extModelDef.getId()==null||extModelDef.getId()==0L)
            throw new ServiceException("更新id不能为空!");
        extModelDef.setUpdateTime(DateUtils.getNowDate());
        extModelDef.setUpdateBy(SecurityUtils.getUsername());
        ExtModelDef oldExtModelDef = extModelDefMapper.selectExtModelDefById(extModelDef.getId());
        int row =  extModelDefMapper.updateExtModelDef(extModelDef);
        //比较数据源名称，如果发生变化，先删除旧表，然后在新数据源，创建新表
        SqlSession sqlSession = null;
        try {
            if (!oldExtModelDef.getDatasourceName().equals(extModelDef.getDatasourceName())) {
                Table t = buildTable(extModelDef.getEnName(), extModelDef.getCnName());
                //List<TableField> tableFields = makeTableFields(extModelDef);
                //如果表类型变化,字段引用表操作
                if(!oldExtModelDef.getTableType().equals(extModelDef.getTableType())) {
                    //删除字段引用表原来的缺省字段
                    deleteDefaultFieldsInReferen(oldExtModelDef);
                    //更新剩余字段的数据源名称
                    updateReferenFieldsDataSourceName(oldExtModelDef,extModelDef);
                    //插入缺省字段
                    insertDefaultFields(extModelDef);
                }else{
                    //更新字段的数据源名称
                    updateReferenFieldsDataSourceName(oldExtModelDef,extModelDef);
                }
                //如果表英文名发生变化，则更新表英文名
                if(!oldExtModelDef.getEnName().equals(extModelDef.getEnName())){
                    //更新字段引用表的表英文名
                    updateReferenFieldsEnName(extModelDef.getDatasourceName(),oldExtModelDef.getEnName(),
                            extModelDef.getEnName());
                }
                //更新业务功能模型关系表的数据源名称，表英文名
                updateBusinessFunctionRelaDsEnName(oldExtModelDef,extModelDef);
                //重新查询当前表字段定义(非缺省字段+新缺省字段)
                List<TableField> tableFields = makeTableAllFields(extModelDef);
                //切换数据源
                String key = dataSourceService.getKey(oldExtModelDef.getEnterpriseCode(),oldExtModelDef.getApplicationCode(),oldExtModelDef.getDatasourceName());
                sqlSession = dataSourceService.switchDataSource(key);
                extModelDefInstanceMapper = sqlSession.getMapper(ExtModelDefInstanceMapper.class);
                extModelDefInstanceMapper.dropTable(oldExtModelDef.getEnName());
                sqlSession.close();
                sqlSession = null;
                key = dataSourceService.getKey(extModelDef.getEnterpriseCode(),extModelDef.getApplicationCode(),extModelDef.getDatasourceName());
                sqlSession = dataSourceService.switchDataSource(key);
                extModelDefInstanceMapper = sqlSession.getMapper(ExtModelDefInstanceMapper.class);
                extModelDefInstanceMapper.createTable(t, tableFields);
            } else {
                //如果表类型变化,字段引用表操作
                List<ExtModelField> oldExtModelFields = null;
                List<TableField> allTableFields =null;
                if(!oldExtModelDef.getTableType().equals(extModelDef.getTableType())) {
                    allTableFields = makeTableAllFields(oldExtModelDef);
                    //查询原来的缺省字段
                    oldExtModelFields = searchDefaultFields(oldExtModelDef);
                    //删除原来的缺省字段
                    deleteDefaultFieldsInReferen(oldExtModelDef);
                    //插入新的缺省字段
                    insertDefaultFields(extModelDef);
                }

                //切换数据源
                String key = dataSourceService.getKey(extModelDef.getEnterpriseCode(),extModelDef.getApplicationCode(),extModelDef.getDatasourceName());
                sqlSession = dataSourceService.switchDataSource(key);
                extModelDefInstanceMapper = sqlSession.getMapper(ExtModelDefInstanceMapper.class);
                //如果表类型变化
                if(!oldExtModelDef.getTableType().equals(extModelDef.getTableType())) {
                    //如果不是删除所有字段
                    if(allTableFields.size()!=oldExtModelFields.size()) {
                        //  则循环删除原来的缺省字段
                        deleteOldDefaultFields(oldExtModelDef.getEnName(), oldExtModelFields);
                        //  循环增加新的缺省字段
                        List<TableField> tableFields = makeTableFields(extModelDef);
                        insertNewDefaultFields(tableFields, oldExtModelDef.getEnName());
                        //如果表英文名发生变化，则更新表英文名
                        if(!oldExtModelDef.getEnName().equals(extModelDef.getEnName())){
                            //更新字段引用表的表英文名
                            updateReferenFieldsEnName(extModelDef.getDatasourceName(),oldExtModelDef.getEnName(),
                                    extModelDef.getEnName());
                            //更新业务功能模型关系表的数据源名称，表英文名
                            updateBusinessFunctionRelaDsEnName(oldExtModelDef,extModelDef);
                        }
                    //重建表
                    }else{
                        //如果表英文名发生变化，则更新表英文名
                        if(!oldExtModelDef.getEnName().equals(extModelDef.getEnName())){
                            //更新字段引用表的表英文名
                            updateReferenFieldsEnName(extModelDef.getDatasourceName(),oldExtModelDef.getEnName(),
                                    extModelDef.getEnName());
                            //更新业务功能模型关系表的数据源名称，表英文名
                            updateBusinessFunctionRelaDsEnName(oldExtModelDef,extModelDef);
                        }
                        Table t = buildTable(extModelDef.getEnName(), extModelDef.getCnName());
                        extModelDefInstanceMapper.dropTable(oldExtModelDef.getEnName());
                        allTableFields = makeTableAllFields(extModelDef);
                        extModelDefInstanceMapper.createTable(t, allTableFields);
                    }
                }else{
                    //如果表英文名发生变化，则更新表英文名
                    if(!oldExtModelDef.getEnName().equals(extModelDef.getEnName())){
                        //更新字段引用表的表英文名
                        updateReferenFieldsEnName(extModelDef.getDatasourceName(),oldExtModelDef.getEnName(),
                                extModelDef.getEnName());
                        //更新业务功能模型关系表的数据源名称，表英文名
                        updateBusinessFunctionRelaDsEnName(oldExtModelDef,extModelDef);
                    }
                }
                //修改表名
                if (!oldExtModelDef.getEnName().equals(extModelDef.getEnName())) {
                    extModelDefInstanceMapper.renameTableName(oldExtModelDef.getEnName(), extModelDef.getEnName());
                }
                //修改表注释
                if (!oldExtModelDef.getCnName().equals(extModelDef.getCnName())) {
                    extModelDefInstanceMapper.changeTableComment(extModelDef);
                }
            }
        }finally {
            if(sqlSession!=null){
                sqlSession.close();
            }
        }
        return row;
    }

    /**
     * 更新功能模型关系表的数据源名称+表英文名
     * @param oldExtModelDef
     * @param extModelDef
     * @return
     */
    private int updateBusinessFunctionRelaDsEnName(ExtModelDef oldExtModelDef, ExtModelDef extModelDef) {
        return extModelBusinessFunctionRelaService.updateBusinessFunctionRelaDsEnName(oldExtModelDef,extModelDef);
    }

    /**
     * 更新字段引用表英文表名
     * @param datasourceName 数据源名称
     * @param oldEnName 旧表名
     * @param newEnName 新表名
     */
    private int updateReferenFieldsEnName(String datasourceName, String oldEnName, String newEnName) {
        return extModelFieldRefMapper.updateReferenFieldsEnName(datasourceName,oldEnName,newEnName);
    }

    /**
     * 插入新的缺省字段
     * @param tableFields
     * @param enName
     */
    private void insertNewDefaultFields(List<TableField> tableFields, String enName) {
        ExtModelField extModelField = new ExtModelField();
        extModelField.setEnName(enName);
        for(TableField tableField:tableFields){
            extModelField.setFieldType(tableField.getFieldType());
            extModelField.setFieldCnName(tableField.getComment());
            extModelField.setFieldEnName(tableField.getFieldName());
            extModelDefInstanceMapper.addField(extModelField);
        }
    }

    /**
     * 删除旧的缺省字段
     * @param enName
     * @param oldExtModelFields
     */
    private void deleteOldDefaultFields(String enName, List<ExtModelField> oldExtModelFields) {
        for(ExtModelField extModelField:oldExtModelFields){
            extModelDefInstanceMapper.dropField(enName,extModelField.getFieldEnName());
        }
    }

    /**
     * 查询缺省字段
     * @param oldExtModelDef
     * @return
     */
    private List<ExtModelField> searchDefaultFields(ExtModelDef oldExtModelDef) {
        ExtModelFieldRef extModelFieldRef = new ExtModelFieldRef();
        if(IBusinessConstant.TABLE_TYPE_01.equals(oldExtModelDef.getTableType())){
            extModelFieldRef.setScope(IBusinessConstant.SCOPE_ENTITY_DEFAULT);
        }else{
            extModelFieldRef.setScope(IBusinessConstant.SCOPE_WORKFLOW_DEFAULT);
        }
        extModelFieldRef.setDatasourceName(oldExtModelDef.getDatasourceName());
        extModelFieldRef.setEnName(oldExtModelDef.getEnName());

        return extModelFieldService.selectExtModelFieldRefByModel(extModelFieldRef);
    }

    /**
     * 查询字段引用表，构造全部字段
     * @param extModelDef
     * @return
     */
    private List<TableField> makeTableAllFields(ExtModelDef extModelDef) {
        //根据数据源名称+表名，查询所有字段
        List<ExtModelField> allFields = extModelFieldService.selectAllFieldsByDsAndEnName(extModelDef);
        boolean isExistId = false;
        List<TableField> tableFields = new ArrayList<>();
        Set<String> notNullFields = new HashSet<>(Arrays.asList("id", "create_by", "create_time"));
        TableField tableField;
        for(ExtModelField field:allFields){
            tableField = new TableField();
            tableField.setFieldName(field.getFieldEnName().toLowerCase());
            tableField.setFieldType(extModelFieldService.getDbType(field.getFieldWidth(),field.getScheme()));
            tableField.setComment(field.getFieldCnName());
            tableField.setPrimaryKey("");
            tableField.setNullLabel("");
            if(field.getFieldEnName().toLowerCase().equals("id")){
                isExistId = true;
                tableField.setAutoIncrement("AUTO_INCREMENT");
                tableField.setPrimaryKey("PRIMARY KEY");
            }
            if(notNullFields.contains(tableField.getFieldName())){
                tableField.setNullLabel("NOT NULL");
            }
            tableFields.add(tableField);
        }
        if(!isExistId)
            throw new ServiceException("缺少id字段!");
        return tableFields;
    }

    /**
     * 删除字段引用表缺省字段
     * @param oldExtModelDef
     */
    private int deleteDefaultFieldsInReferen(ExtModelDef oldExtModelDef) {
        ExtModelFieldRef extModelFieldRef = new ExtModelFieldRef();
        if(IBusinessConstant.TABLE_TYPE_01.equals(oldExtModelDef.getTableType())){
            extModelFieldRef.setScope(IBusinessConstant.SCOPE_ENTITY_DEFAULT);
        }else{
            extModelFieldRef.setScope(IBusinessConstant.SCOPE_WORKFLOW_DEFAULT);
        }
        extModelFieldRef.setDatasourceName(oldExtModelDef.getDatasourceName());
        extModelFieldRef.setEnName(oldExtModelDef.getEnName());

        return extModelFieldRefMapper.deleteExtModelFieldRefByModel(extModelFieldRef);
    }

    /**
     * 更新字段引用表数据源名称
     * @param oldExtModelDef
     * @param extModelDef
     */
    private int updateReferenFieldsDataSourceName(ExtModelDef oldExtModelDef, ExtModelDef extModelDef) {
        return extModelFieldRefMapper.updateReferenFieldsDataSourceName(oldExtModelDef,extModelDef.getDatasourceName());
    }

    /**
     * 批量删除模型定义
     *
     * @param ids 需要删除的模型定义主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteExtModelDefByIds(Long[] ids)
    {
        int sum =0;
        for(Long id:ids){
            sum +=deleteExtModelDefById(id);
        }
        return sum;
    }

    /**
     * 删除模型定义信息
     *
     * @param id 模型定义主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteExtModelDefById(Long id)
    {
        ExtModelDef extModelDef = extModelDefMapper.selectExtModelDefById(id);
        if(extModelDef==null)
            throw new ServiceException("无效的模型表定义id:"+id);
        //删除关联的业务功能模型关系表
        extModelFieldService.deleteExtModelFieldByTableName(extModelDef);
        ExtModelBusinessFunctionRela functionRela = new ExtModelBusinessFunctionRela();
        functionRela.setEnName(extModelDef.getEnName());
        functionRela.setDatasourceName(extModelDef.getDatasourceName());
        extModelBusinessFunctionRelaService.deleteExtModelBusinessFunctionRela(functionRela);
        int row =  extModelDefMapper.deleteExtModelDefById(id);
        //切换数据源
        SqlSession sqlSession = null;
        try {
            String key = dataSourceService.getKey(extModelDef.getEnterpriseCode(),extModelDef.getApplicationCode(),extModelDef.getDatasourceName());
            sqlSession = dataSourceService.switchDataSource(key);
            extModelDefInstanceMapper = sqlSession.getMapper(ExtModelDefInstanceMapper.class);
            //删除表
            extModelDefInstanceMapper.dropTable(extModelDef.getEnName());
        }finally {
            if(sqlSession!=null){
                sqlSession.close();
            }
        }
        return row;
    }

    /**
     * @param instanceFindParam
     * @return
     */
    @Override
    public Map<String, Object> getInstance(ExtModelDefInstanceOne instanceFindParam) {
        //切换数据源
        SqlSession sqlSession=null;
        try {
            //获取数据源名称
            String datasourceName = getDataSourceName(instanceFindParam.getDataSourceName(),instanceFindParam.getInterfaceCode());
            //
            String key = dataSourceService.getKey(SecurityUtils.getEnterpriseCode(),SecurityUtils.getApplicationCode(),datasourceName);
            sqlSession = dataSourceService.switchDataSource(key);
            extModelDefInstanceMapper = sqlSession.getMapper(ExtModelDefInstanceMapper.class);
            return extModelDefInstanceMapper.getInstance(instanceFindParam);
        }finally {
            if(sqlSession!=null){
                sqlSession.close();
            }
        }
    }

    /**
     *  获取数据源名称，如果数据源名称为空，则尝试根据接口编码获取关联的数据源，如果能拿到则返回；否则抛出异常
     * @param dataSourceName
     * @param interfaceCode
     * @return
     */
    private String getDataSourceName(String dataSourceName, String interfaceCode) {
        if(StringUtils.isEmpty(dataSourceName)){
            //根据接口编码获取数据源名称
            ExtInterface searchExtInterface = new ExtInterface();
            searchExtInterface.setInterfaceCode(interfaceCode);
            List<ExtInterface> interfaceList = extInterfaceMapper.selectExtInterfaceList(searchExtInterface);

            if(CollectionUtils.isEmpty(interfaceList))
                throw new ServiceException("未找到接口编码:"+interfaceCode);

            String returnDataSourceName = interfaceList.get(0).getInterfaceDatasourceName();
            if(StringUtils.isEmpty(returnDataSourceName))
                throw new ServiceException("未传数据源名称参数且接口:"+interfaceCode+"未配置数据源");
            return returnDataSourceName;
        }
        return dataSourceName;
    }

    /**
     * 插入实例记录
     *
     * @param param
     * @return
     */
    @Override
    public ExtModelDefInstanceAdd createInstance(ExtModelDefInstanceAdd param) {
        //切换数据源
        SqlSession sqlSession=null;
        try {
            //获取数据源名称
            String datasourceName = getDataSourceName(param.getDataSourceName(),param.getInterfaceCode());
            //
            String key = dataSourceService.getKey(SecurityUtils.getEnterpriseCode(),SecurityUtils.getApplicationCode(),datasourceName);
            sqlSession = dataSourceService.switchDataSource(key);
            extModelDefInstanceMapper = sqlSession.getMapper(ExtModelDefInstanceMapper.class);
            List<ExtModelDefInstanceField> instanceFields = makeInstanceFields(datasourceName, param.getEnName(), param.getData(),true);
            extModelDefInstanceMapper.createInstance(param,instanceFields);
            log.info("param:"+ JSON.toJSONString(param));
            return param;
        }finally {
            if(sqlSession!=null){
                sqlSession.close();
            }
        }
    }

    /**
     * 更新实例记录
     *
     * @param param
     * @return
     */
    @Override
    public ExtModelDefInstanceUpdate updateInstance(ExtModelDefInstanceUpdate param) {
        SqlSession sqlSession=null;
        try {
            //获取数据源名称
            String datasourceName = getDataSourceName(param.getDataSourceName(),param.getInterfaceCode());
            //
            String key = dataSourceService.getKey(SecurityUtils.getEnterpriseCode(),SecurityUtils.getApplicationCode(),datasourceName);
            sqlSession = dataSourceService.switchDataSource(key);
            extModelDefInstanceMapper = sqlSession.getMapper(ExtModelDefInstanceMapper.class);
            List<ExtModelDefInstanceField> instanceFields = makeInstanceFields(datasourceName, param.getEnName(), param.getData(),false);
            extModelDefInstanceMapper.updateInstance(param.getId(),param.getEnName(),instanceFields);
            return param;
        }finally {
            if(sqlSession!=null){
                sqlSession.close();
            }
        }
    }

    /**
     * 根据数据源+表英文名+id,删除实例记录
     *
     * @param param
     */
    @Override
    public void deleteInstance(ExtModelDefInstanceOne param) {
        //切换数据源
        SqlSession sqlSession=null;
        try {
            //获取数据源名称
            String datasourceName = getDataSourceName(param.getDataSourceName(),param.getInterfaceCode());
            //
            String key = dataSourceService.getKey(SecurityUtils.getEnterpriseCode(),SecurityUtils.getApplicationCode(),datasourceName);
            sqlSession = dataSourceService.switchDataSource(key);
            extModelDefInstanceMapper = sqlSession.getMapper(ExtModelDefInstanceMapper.class);
            extModelDefInstanceMapper.deleteInstance(param.getId(),param.getEnName());
        }finally {
            if(sqlSession!=null){
                sqlSession.close();
            }
        }
    }

    @Override
    public List<BusinessFunctionTree> treeList(ExtModelDef extModelDef) {
        ExtBusinessFunction extBusinessFunction = new ExtBusinessFunction();
        List<BusinessFunctionTree> tree = extBusinessFunctionService.selectCommonBusinessFunctionTree(extBusinessFunction);
        //查询模型定义列表
        List<ExtModelDef> extModelDefList = extModelDefMapper.selectModelDefListAssignBusinessFunction(extModelDef);
        fillTreeWithModelDefList(tree,extModelDefList);
        return tree;
    }

    @Override
    public List<Map<String, Object>> listInstance(ExtModelDefInstanceList extModelDefInstanceList, PageDomain pageDomain) {
        //切换数据源
        SqlSession sqlSession=null;
        try {
            //获取数据源名称
            String datasourceName = getDataSourceName(extModelDefInstanceList.getDataSourceName(),extModelDefInstanceList.getInterfaceCode());
            //查询接口编码对应的sql
            ExtInterface extInterface = new ExtInterface();
            extInterface.setInterfaceCode(extModelDefInstanceList.getInterfaceCode());
            List<ExtInterface> interfaces = extInterfaceMapper.selectExtInterfaceList(extInterface);
            if(CollectionUtils.isNotEmpty(interfaces)) {
                //取出接口定义sql
                ExtInterface interface1 = interfaces.get(0);
                if(!com.ruoyi.common.core.utils.StringUtils.isEmpty(interface1.getProduceSql())) {
                    //
                    String key = dataSourceService.getKey(SecurityUtils.getEnterpriseCode(),SecurityUtils.getApplicationCode(),datasourceName);
                    sqlSession = dataSourceService.switchDataSource(key);
                    try {
                        String pageSql = makePageSql(datasourceName,pageDomain,interface1.getProduceSql());
                        return sqlService.search(sqlSession.getConnection(),pageSql,extModelDefInstanceList.getSearchCondition());
                    } catch (Exception e) {
                        log.error("查询sql语句:"+interface1.getProduceSql()+"失败!",e);
                        throw new ServiceException("接口:"+extModelDefInstanceList.getInterfaceCode()+"查询sql语句失败!");
                    }
                }else
                    throw new ServiceException("接口:"+extModelDefInstanceList.getInterfaceCode()+"查询sql语句为空!");
            }else
                throw new ServiceException("接口:"+extModelDefInstanceList.getInterfaceCode()+"尚未定义!");

        }finally {
            if(sqlSession!=null){
                sqlSession.close();
            }
        }
    }

    /**
     * 非翻页查询
     * @param extModelDefInstanceList
     * @return
     */
    @Override
    public List<Map<String, Object>> listAllInstance(ExtModelDefInstanceList extModelDefInstanceList) {
        //切换数据源
        SqlSession sqlSession=null;
        try {
            //获取数据源名称
            String datasourceName = getDataSourceName(extModelDefInstanceList.getDataSourceName(),extModelDefInstanceList.getInterfaceCode());
            //查询接口编码对应的sql
            ExtInterface extInterface = new ExtInterface();
            extInterface.setInterfaceCode(extModelDefInstanceList.getInterfaceCode());
            List<ExtInterface> interfaces = extInterfaceMapper.selectExtInterfaceList(extInterface);
            if(CollectionUtils.isNotEmpty(interfaces)) {
                //取出接口定义sql
                ExtInterface interface1 = interfaces.get(0);
                if(!com.ruoyi.common.core.utils.StringUtils.isEmpty(interface1.getProduceSql())) {
                    //
                    String key = dataSourceService.getKey(SecurityUtils.getEnterpriseCode(),SecurityUtils.getApplicationCode(),datasourceName);
                    sqlSession = dataSourceService.switchDataSource(key);
                    try {
                        return sqlService.search(sqlSession.getConnection(),interface1.getProduceSql(),extModelDefInstanceList.getSearchCondition());
                    } catch (Exception e) {
                        log.error("查询sql语句:"+interface1.getProduceSql()+"失败!",e);
                        throw new ServiceException("接口:"+extModelDefInstanceList.getInterfaceCode()+"查询sql语句失败!");
                    }
                }else
                    throw new ServiceException("接口:"+extModelDefInstanceList.getInterfaceCode()+"查询sql语句为空!");
            }else
                throw new ServiceException("接口:"+extModelDefInstanceList.getInterfaceCode()+"尚未定义!");

        }finally {
            if(sqlSession!=null){
                sqlSession.close();
            }
        }
    }

    @Override
    public int countInstance(ExtModelDefInstanceList extModelDefInstanceList) {
        //切换数据源
        SqlSession sqlSession=null;
        try {
            //获取数据源名称
            String datasourceName = getDataSourceName(extModelDefInstanceList.getDataSourceName(),extModelDefInstanceList.getInterfaceCode());
            //查询接口编码对应的sql
            ExtInterface extInterface = new ExtInterface();
            extInterface.setInterfaceCode(extModelDefInstanceList.getInterfaceCode());
            List<ExtInterface> interfaces = extInterfaceMapper.selectExtInterfaceList(extInterface);
            if(CollectionUtils.isNotEmpty(interfaces)) {
                //取出接口定义sql
                ExtInterface interface1 = interfaces.get(0);
                if(!com.ruoyi.common.core.utils.StringUtils.isEmpty(interface1.getProduceSql())) {
                    //
                    String key = dataSourceService.getKey(SecurityUtils.getEnterpriseCode(),SecurityUtils.getApplicationCode(),datasourceName);
                    sqlSession = dataSourceService.switchDataSource(key);
                    try {
                        String countSql = makeCountSql(interface1.getProduceSql());
                        List<Map<String, Object>> maps = sqlService.search(sqlSession.getConnection(), countSql, extModelDefInstanceList.getSearchCondition());
                        Map<String,Object> map = maps.get(0);
                        return Integer.valueOf((String)map.get(IBusinessConstant.COUNT_FIELD));
                    } catch (Exception e) {
                        log.error("查询sql语句:"+interface1.getProduceSql()+"失败!",e);
                        throw new ServiceException("接口:"+extModelDefInstanceList.getInterfaceCode()+"查询sql语句失败!");
                    }
                }else
                    throw new ServiceException("接口:"+extModelDefInstanceList.getInterfaceCode()+"查询sql语句为空!");
            }else
                throw new ServiceException("接口:"+extModelDefInstanceList.getInterfaceCode()+"尚未定义!");

        }finally {
            if(sqlSession!=null){
                sqlSession.close();
            }
        }
    }

    /**
     * 构造统计个数sql
     * @param produceSql
     * @return
     */
    private String makeCountSql(String produceSql) {
        String countSql;
        countSql = String.format("select count(*) %s from(%s) tmp ",IBusinessConstant.COUNT_FIELD,produceSql);
        return countSql;
    }

    /**
     * 构造翻页sql
     * @param datasourceName
     * @param pageDomain
     * @param produceSql
     * @return
     */
    private String makePageSql(String datasourceName, PageDomain pageDomain, String produceSql) {
        ExtModelDatasource searchVo = new ExtModelDatasource();
        searchVo.setDatasourceName(datasourceName);
        List<ExtModelDatasource> vos = extModelDatasourceService.selectExtModelDatasourceList(searchVo);
        if(CollectionUtils.isEmpty(vos))
            throw new ServiceException("数据源名称："+datasourceName+"不存在!");
        ExtModelDatasource extModelDatasource = vos.get(0);
        String returnSql="";
        switch (extModelDatasource.getDbType()) {
            case IBusinessConstant.DATABASE_TYPE_MYSQL:
            returnSql = String.format("%s LIMIT %d\n" +
                    "OFFSET %d", produceSql, pageDomain.getPageSize(), (pageDomain.getPageNum() - 1) * pageDomain.getPageSize());
        }
        return returnSql;
    }

    /**
     * 填充树节点
     * @param tree
     * @param extModelDefList
     */
    private void fillTreeWithModelDefList(List<BusinessFunctionTree> tree, List<ExtModelDef> extModelDefList) {
        for(BusinessFunctionTree node:tree){
            recursionFillTree(node,extModelDefList);
        }
    }


    /**
     * 递归填充树节点
     * @param node 树节点
     * @param extModelDefList
     */
    private void recursionFillTree(BusinessFunctionTree node, List<ExtModelDef> extModelDefList) {
        //如果有下级节点，则递归下级，直到没有下级
        if(node.getChildren()!=null && node.getChildren().size()>0){
            for(BusinessFunctionTree child:node.getChildren()){
                recursionFillTree(child,extModelDefList);
            }
        }else{
            //查询属于当前业务编码的接口列表
            List<ExtModelDef> childList = extModelDefList.stream().filter(extModelDef -> extModelDef.getBusinessCode().equals(node.getValue())).collect(Collectors.toList());
            node.setChildren(toBusinessFunctionTreeList(node.getValue(),childList));
        }
    }

    /**
     * 转换接口列表为业务功能树列表
     *
     * @param parentCode
     * @param childList
     * @return
     */
    private List<BusinessFunctionTree> toBusinessFunctionTreeList(String parentCode, List<ExtModelDef> childList) {
        List<BusinessFunctionTree> retList = new ArrayList<>();
        for(ExtModelDef child:childList){
            childList.forEach(extModelDef -> {
                BusinessFunctionTree businessFunctionTree = new BusinessFunctionTree();
                businessFunctionTree.setValue(String.valueOf(extModelDef.getId()));
                businessFunctionTree.setLabel(extModelDef.getCnName());
                businessFunctionTree.setParentCode(parentCode);
                retList.add(businessFunctionTree);
            });
        }
        return retList;
    }
    /**
     * 构造实例字段
     * @param dataSourceName 数据源
     * @param enName 表英文名
     * @param recordData 记录数据
     * @param bInsert 是否是插入
     * @return
     */
    private List<ExtModelDefInstanceField> makeInstanceFields(String dataSourceName, String enName, Map<String,Object> recordData,boolean bInsert) {
        //根据表类型查询缺省字段
        ExtModelField extModelField = new ExtModelField();
        ExtModelDef searchExtModelDef = new ExtModelDef();

        searchExtModelDef.setDatasourceName(dataSourceName);
        searchExtModelDef.setEnName(enName);
        List<ExtModelDef> extModelDefs = extModelDefMapper.selectExtModelDefList(searchExtModelDef);
        if(CollectionUtils.isEmpty(extModelDefs))
            throw new ServiceException("无效的表英文名:"+enName);
        ExtModelDef extModelDef = extModelDefs.get(0);
        if(IBusinessConstant.TABLE_TYPE_01.equals(extModelDef.getTableType())){
            extModelField.setScope(IBusinessConstant.SCOPE_ENTITY_DEFAULT);
        }else{
            extModelField.setScope(IBusinessConstant.SCOPE_WORKFLOW_DEFAULT);
        }

        List<ExtModelField> allFields = extModelFieldMapper.selectAllFieldsByDsAndEnName(searchExtModelDef);

        List<com.ruoyi.business.entity.ExtModelDefInstanceField> instanceFields = new ArrayList<>();
        List<String> defaultFieldNames = makeDefaultFieldNames();
        ExtModelDefInstanceField instanceField;
        for(ExtModelField field:allFields){
            //非缺省字段为空值，忽略
            String fieldProps = field.getFieldEnName().toLowerCase();
            //企业编码和应用编码字段不能跳过
            if(!fieldProps.equals("enterprise_code") && !fieldProps.equals("application_code")) {
                if (!defaultFieldNames.contains(fieldProps)) {
                    if (recordData.get(fieldProps) == null) {
                        continue;
                    }
                }
            }
            instanceField = new ExtModelDefInstanceField();
            instanceField.setFieldName(fieldProps);
            instanceField.setFieldValue(recordData.get(fieldProps));
            if(bInsert) {
                if (field.getFieldEnName().toLowerCase().equals("create_by")) {
                    instanceField.setFieldValue(SecurityUtils.getUserId());
                } else if (field.getFieldEnName().toLowerCase().equals("create_time")) {
                    instanceField.setFieldValue(DateUtils.getNowDate());
                }
            }else{
                if (field.getFieldEnName().toLowerCase().equals("update_by")) {
                    instanceField.setFieldValue(SecurityUtils.getUserId());
                } else if (field.getFieldEnName().toLowerCase().equals("update_time")) {
                    instanceField.setFieldValue(DateUtils.getNowDate());
                }
            }
            //设置企业编码和应用编码
            if(field.getFieldEnName().toLowerCase().equals("enterprise_code")) {
                instanceField.setFieldValue(SecurityContextHolder.getEnterpriseCode());
            }
            if(field.getFieldEnName().toLowerCase().equals("application_code")) {
                instanceField.setFieldValue(SecurityContextHolder.getApplicationCode());
            }

            instanceFields.add(instanceField);
        }
        if(instanceFields.isEmpty())
            throw new ServiceException("没有需要保存的字段");
        return instanceFields;
    }

    /**
     * 构造缺省字段名列表
     * @return
     */
    private List<String> makeDefaultFieldNames() {
        List<String> defaultFieldNames = new ArrayList<>();

        defaultFieldNames.add("create_by");
        defaultFieldNames.add("create_time");
        defaultFieldNames.add("update_by");
        defaultFieldNames.add("update_time");
        return defaultFieldNames;
    }

}
